using Glpt.Common;
using Glpt.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Glpt.Task
{
    /// <summary>
    /// 调用cmd或sql命令任务
    /// </summary>
    public class SqlcmdTask
    {
        private BackgroundWorker bwt = null;
        private const string ATTR_PARAM_VALUE = "@PARAM_VALUE";
        private Dictionary<string, bool> cond_result = new Dictionary<string, bool>();
        private Dictionary<string, string> exec_params = new Dictionary<string, string>();
        private int MAX_SQLCMD_ID = 0;
        private DataTable msg = new DataTable("Table1");
        private Object task_Lock = new Object();
        /// <summary>
        /// 是否断点续做
        /// </summary>
        private bool IsContinue = true;
        /// <summary>
        /// 初始化类的新实例
        /// </summary>
        public SqlcmdTask()
        {
        }
        /// <summary>
        /// 参数设置
        /// </summary>
        /// <param name="iscon">0重头执行 1断点续做</param>
        public void SetParams(string iscon)
        {
            IsContinue = iscon.Equals("1");
        }
        /// <summary>
        /// 测试接口
        /// </summary>
        /// <param name="function_id">功能号</param>
        /// <param name="tradedate">业务日期</param>
        /// <returns>日志信息</returns>
        public DataTable SetParams(string function_id, string tradedate)
        {
            return SetParams(function_id, tradedate, "");
        }
        /// <summary>
        /// 测试接口
        /// </summary>
        /// <param name="function_id">功能号</param>
        /// <param name="tradedate">业务日期</param>
        /// <param name="exec_value">参数值</param>
        /// <returns>日志信息</returns>
        public DataTable SetParams(string function_id, string tradedate, string exec_value)
        {
            return SetParams(0, function_id, "", tradedate, exec_value);
        }
        /// <summary>
        /// 参数设置
        /// </summary>
        /// <param name="db_no">数据库编号</param>
        /// <param name="function_id">功能编号</param>
        /// <param name="task_id">任务编号</param>
        /// <param name="tradedate">业务日期</param>
        /// <returns>日志信息</returns>
        public DataTable SetParams(int db_no, string function_id, string task_id, string tradedate)
        {
            return SetParams(db_no, function_id, task_id, tradedate, "");
        }
        /// <summary>
        /// 参数设置
        /// </summary>
        /// <param name="db_no">数据库编号</param>
        /// <param name="function_id">功能编号</param>
        /// <param name="task_id">任务编号</param>
        /// <param name="tradedate">业务日期</param>
        /// <param name="exec_value">参数值</param>
        /// <returns>日志信息</returns>
        public DataTable SetParams(int db_no, string function_id, string task_id, string tradedate, string exec_value)
        {
            string sqlcmd_id_name = "";
            string param_value = "";
            if (exec_value.StartsWith(":"))
                sqlcmd_id_name = exec_value.Substring(1);
            else
                param_value = exec_value;
            BaseInterFace bif = new BaseInterFace(db_no);
            string sql = "SELECT * FROM TB_SQLCMD_LIST WHERE TASK_FUNCTION_ID=" + function_id + " AND ENABLE_FLAG='1'";
            if (sqlcmd_id_name.Length > 0)
            {
                if (Funcs.IsInt(sqlcmd_id_name))
                    sql += " AND SQLCMD_ID=" + sqlcmd_id_name;
                else
                    sql += " AND GROUP_NAME LIKE '" + sqlcmd_id_name + "'";
            }
            sql += " ORDER BY SQLCMD_ID";
            DataTable dt_list = bif.ExecSelect(sql);
            DataRow[] drst = dt_list.Select("SQLCMD_ID=-1");//动态取
            if (drst.Length > 0)
            {
                string exp = drst[0]["PARAM_LIST"].ToString();
                string dbno = drst[0]["DB_NO"].ToString();
                if (!exp.Contains(":") && dbno.Length > 0) exp = dbno + ":" + exp;
                dt_list = CommFuns.GetDynamicProc(dt_list, exp, function_id, tradedate);
            }
            if (!IsContinue && task_id.Length > 0)
            {
                sql = "DELETE FROM TB_SQLCMD_LOG WHERE TASK_ID=" + task_id;
                bif.ExecUpdate(sql);
            }
            int.TryParse(dt_list.Compute("MAX(SQLCMD_ID)", "").ToString(), out MAX_SQLCMD_ID);
            if (MAX_SQLCMD_ID < 10000) MAX_SQLCMD_ID = 10000;
            msg.Columns.Add("SQLCMD_ID");
            msg.Columns.Add("LOG_MESSAGE");

            Dictionary<string, List<DataRow>> group_list = new Dictionary<string, List<DataRow>>();
            foreach (DataRow dr in dt_list.Rows)
            {
                string GROUP_NAME = dr["GROUP_NAME"].ToString();
                if (!group_list.ContainsKey(GROUP_NAME))
                {
                    group_list.Add(GROUP_NAME, new List<DataRow>());
                }
                group_list[GROUP_NAME].Add(dr);
            }
            if (group_list.Count > 1)
            {
                Exception taskException = null;//错误信息
                ParallelOptions opt = new ParallelOptions();
                opt.MaxDegreeOfParallelism = 2;
                Parallel.ForEach(group_list, opt, (item, state) =>//并行
                {
                    if (taskException != null)
                        state.Break();
                    else
                    {
                        if (bwt != null && bwt.CancellationPending)
                            taskException = new Exception("线程被取消");
                        else
                        {
                            try
                            {
                                ExecuteThread(item.Value, db_no, function_id, task_id, tradedate, param_value);
                            }
                            catch (Exception ex)
                            {
                                taskException = ex;
                            }
                        }
                    }
                });
                if (taskException != null)
                    throw new Exception(taskException.Message, taskException);
            }
            else if (group_list.Count == 1)
                ExecuteThread(group_list.Values.First(), db_no, function_id, task_id, tradedate, param_value);
            return msg;
        }

        private void ExecuteThread(List<DataRow> lsr, int db_no, string function_id, string task_id, string tradedate, string param_value)
        {
            string sql = "";
            BaseInterFace bif = new BaseInterFace(db_no);
            foreach (DataRow dr in lsr)
            {
                if (bwt != null && bwt.CancellationPending)
                    throw new Exception("线程被取消");
                string COND_EXP = Funcs.ReplaceWord(dr["COND_EXP"].ToString().Trim(), tradedate).Replace(ATTR_PARAM_VALUE, param_value);//条件函数
                if (COND_EXP.Length > 0)
                {
                    lock (task_Lock)
                    {
                        bool fx = COND_EXP.StartsWith("!");//反向条件
                        if (fx) COND_EXP = COND_EXP.Substring(1);
                        if (COND_EXP.StartsWith("@"))//相同条件
                        {
                            COND_EXP = COND_EXP.Substring(1);
                            if (Funcs.IsInt(COND_EXP))
                            {
                                DataRow[] drs = dr.Table.Select("SQLCMD_ID=" + COND_EXP);
                                if (drs.Length > 0)
                                    COND_EXP = Funcs.ReplaceWord(drs[0]["COND_EXP"].ToString().Trim(), tradedate).Replace(ATTR_PARAM_VALUE, param_value);
                                else
                                    throw new Exception("没有找到指定编号的条件");
                            }
                        }
                        bool result = true;
                        if (cond_result.ContainsKey(COND_EXP))
                            result = cond_result[COND_EXP];
                        else
                        {
                            if (COND_EXP.Contains("?"))
                            {
                                string forwarddll = COND_EXP;
                                int idx = forwarddll.IndexOf("#");
                                object[] execParams = new object[] { tradedate };
                                if (idx > 0)
                                {
                                    forwarddll = COND_EXP.Substring(0, idx);
                                    execParams = DataFuns.SplitString(COND_EXP.Substring(idx + 1), ',', true).ToArray();
                                }
                                if (forwarddll.Equals("?"))
                                {
                                    bool check_use = false;
                                    if (execParams.Length > 1) check_use = execParams[1].ToString().Equals("1");
                                    if (execParams.Length == 1 || execParams.Length == 2)
                                        result = (FilePath.CheckFileExist(execParams[0].ToString(), check_use) == 1);
                                    else
                                        result = false;
                                }
                                else
                                {
                                    object obj = InvokeDynamic.CreateObject(forwarddll);
                                    object val = InvokeDynamic.InvokeMember(obj, execParams);
                                    result = (val != null && val.ToString().Equals("1"));
                                }
                            }
                            else
                                result = CommFuns.GetDynamicFunc(bif, COND_EXP, "").Rows[0][0].ToString().Equals("1");
                            cond_result.Add(COND_EXP, result);
                        }
                        if (fx) result = !result;
                        if (!result)
                            continue;
                    }
                }
                string BUSI_DATE = tradedate;
                string DATE_EXP = Funcs.ReplaceWord(dr["DATE_EXP"].ToString(), BUSI_DATE).Replace(ATTR_PARAM_VALUE, param_value);
                int ParamsCount = 1;
                DataTable dt_params = null;
                if (DATE_EXP.Length > 0)
                {
                    lock (task_Lock)
                    {
                        dt_params = CommFuns.GetDynamicFunc(bif, DATE_EXP, "BUSI_DATE");
                        ParamsCount = dt_params.Rows.Count;
                        if (ParamsCount == 0)
                            continue;
                        else if (ParamsCount == 1)
                            CommFuns.AddParams(exec_params, dt_params);
                        if (exec_params.ContainsKey("@BUSI_DATE") && exec_params["@BUSI_DATE"].Length > 0)
                            BUSI_DATE = exec_params["@BUSI_DATE"];
                        if (exec_params.ContainsKey("@BEGIN_DATE") && exec_params["@BEGIN_DATE"].Length == 8 && !exec_params.ContainsKey("@C_BEGIN_DATE"))
                            CommFuns.AddParams(exec_params, "C_BEGIN_DATE", Funcs.StrToDataTime(exec_params["@BEGIN_DATE"]).ToString("yyyy-MM-dd"));
                        if (exec_params.ContainsKey("@END_DATE") && exec_params["@END_DATE"].Length == 8 && !exec_params.ContainsKey("@C_END_DATE"))
                            CommFuns.AddParams(exec_params, "C_END_DATE", Funcs.StrToDataTime(exec_params["@END_DATE"]).ToString("yyyy-MM-dd"));
                    }
                }
                for (int i = 0; i < ParamsCount; i++)
                {
                    DbParamCollection sql_params = null;
                    string SQLCMD_ID = (i == 0 ? dr["SQLCMD_ID"].ToString() : (++MAX_SQLCMD_ID).ToString());
                    if (task_id.Length > 0)
                    {
                        sql_params = new DbParamCollection();
                        sql_params.Add(new DbParam("TASK_ID", task_id, DbParamType.VarChar, false));
                        sql_params.Add(new DbParam("SQLCMD_ID", SQLCMD_ID, DbParamType.Int, false));
                        if (IsContinue)
                        {
                            sql = "SELECT * FROM TB_SQLCMD_LOG WHERE TASK_ID=" + bif.ParamChar + "TASK_ID AND SQLCMD_ID=" + bif.ParamChar + "SQLCMD_ID";
                            if (bif.ExecSelect(sql, sql_params).Rows.Count > 0)
                                continue;
                        }
                    }
                    string CMD_NAME = Funcs.ReplaceWord(dr["CMD_NAME"].ToString(), BUSI_DATE).Trim();
                    string PARAM_LIST = Funcs.ReplaceWord(dr["PARAM_LIST"].ToString(), BUSI_DATE).Replace(ATTR_PARAM_VALUE, param_value).Trim();
                    if (ParamsCount > 1)
                    {
                        foreach (DataColumn dc in dt_params.Columns)
                        {
                            string param_name = "@" + dc.ColumnName;
                            string data_value = dt_params.Rows[i][dc].ToString();
                            CMD_NAME = CMD_NAME.Replace(param_name, Funcs.ReplaceWord(data_value, BUSI_DATE));
                            PARAM_LIST = PARAM_LIST.Replace(param_name, Funcs.ReplaceWord(data_value, BUSI_DATE));
                        }
                    }
                    foreach (string param_name in exec_params.Keys)
                    {
                        CMD_NAME = CMD_NAME.Replace(param_name, Funcs.ReplaceWord(exec_params[param_name], BUSI_DATE));
                        PARAM_LIST = PARAM_LIST.Replace(param_name, Funcs.ReplaceWord(exec_params[param_name], BUSI_DATE));
                    }
                    PARAM_LIST = PARAM_LIST.Replace("@TASK_ID", task_id);
                    string LOG_MESSAGE = "";
                    DateTime EXECUTE_START_TIME = DateTime.Now;
                    if (CMD_NAME.ToLower().Equals("sql"))
                    {
                        int u_db_no = 0;
                        DbItem dbi = null;
                        string s_db_no = dr["DB_NO"].ToString();
                        if (exec_params.ContainsKey("@DB_NO") && exec_params["@DB_NO"].Length > 0)
                            s_db_no = exec_params["@DB_NO"];
                        if (int.TryParse(s_db_no, out u_db_no))
                        {
                            dbi = CommFuns.GetDbItem(u_db_no, tradedate);
                        }
                        else
                            throw new Exception("数据库编号不正确");
                        if (PARAM_LIST.Length > 0)
                        {
                            object[] PMS = CommFuns.SplitSQL(dbi.DB_TYPE, PARAM_LIST);//分拆SQL语句
                            new BaseInterFace(dbi).ExecUpdate(bwt, (string)PMS[0], (DbParamCollection)PMS[1], (bool)PMS[2]);
                        }
                    }
                    else if (CMD_NAME.ToLower().Contains(".dll?"))
                    {
                        object[] execParams = DataFuns.SplitString(PARAM_LIST, ',', true).ToArray();
                        object obj = InvokeDynamic.CreateObject(CMD_NAME);
                        InvokeDynamic.SetPropertyInfo(obj, "BackgroundWorkerTask", BackgroundWorkerTask);
                        object ret = InvokeDynamic.InvokeMember(obj, execParams);
                        if (ret != null)
                        {
                            LOG_MESSAGE = ret.ToString();
                            if (LOG_MESSAGE.Length > 0 && !LOG_MESSAGE.EndsWith("。")) LOG_MESSAGE += "。";
                        }
                    }
                    else if (CMD_NAME.ToLower().Equals("dll"))
                    {
                        string forwarddll = PARAM_LIST;
                        int idx = forwarddll.IndexOf("#");
                        object[] execParams = new object[] { BUSI_DATE };
                        if (idx > 0)
                        {
                            forwarddll = PARAM_LIST.Substring(0, idx);
                            execParams = DataFuns.SplitString(PARAM_LIST.Substring(idx + 1), ',', true).ToArray();
                        }
                        object obj = InvokeDynamic.CreateObject(forwarddll);
                        InvokeDynamic.SetPropertyInfo(obj, "BackgroundWorkerTask", BackgroundWorkerTask);
                        object ret = InvokeDynamic.InvokeMember(obj, execParams);
                        if (ret != null)
                        {
                            LOG_MESSAGE = ret.ToString();
                            if (LOG_MESSAGE.Length > 0 && !LOG_MESSAGE.EndsWith("。")) LOG_MESSAGE += "。";
                        }
                    }
                    else if (CMD_NAME.ToLower().Equals("copy"))
                    {
                        List<string> args = DataFuns.SplitString(PARAM_LIST, ',', true);
                        if (args.Count < 2) throw new Exception("参数错误");
                        string source = args[0];
                        string destination = args[1];
                        bool overwrite = true;
                        if (args.Count > 2) overwrite = args[2].Equals("1");
                        int icount = CopyFileTask.CopyFiles(source, destination, SearchOption.AllDirectories, "", overwrite);
                        LOG_MESSAGE = "复制了 " + icount.ToString() + " 个文件。";
                    }
                    else if (CMD_NAME.ToLower().Equals("move"))
                    {
                        List<string> args = DataFuns.SplitString(PARAM_LIST, ',', true);
                        if (args.Count < 2) throw new Exception("参数错误");
                        string source = args[0];
                        string destination = args[1];
                        if (source.Contains("*") || source.Contains("?"))
                        {
                            int idx = source.LastIndexOf(DataFuns.DirSeparator);
                            if (idx > 0)
                            {
                                DirectoryInfo dinfo = new DirectoryInfo(source.Substring(0, idx));
                                if (dinfo.Exists)
                                {
                                    FileInfo[] files = dinfo.GetFiles(source.Substring(idx + 1), SearchOption.TopDirectoryOnly);
                                    foreach (FileInfo file in files)
                                    {
                                        string destination2 = destination;
                                        if (!destination2.Contains(DataFuns.DirSeparator))
                                            destination2 = Path.Combine(file.DirectoryName, destination);
                                        if (Directory.Exists(destination2) || destination2.EndsWith(DataFuns.DirSeparator)) destination2 = Path.Combine(destination2, file.Name);
                                        FileInfo file2 = new FileInfo(destination2);
                                        if (!file2.Directory.Exists) file2.Directory.Create();
                                        if (file2.Exists) file2.Delete();
                                        file.MoveTo(destination2);
                                    }
                                    LOG_MESSAGE = "成功。";
                                }
                            }
                            if (LOG_MESSAGE.Length == 0)
                                LOG_MESSAGE = "找不到文件。";
                        }
                        else
                        {
                            FileInfo file = new FileInfo(source);
                            if (file.Exists)
                            {
                                string destination2 = destination;
                                if (!destination2.Contains(DataFuns.DirSeparator))
                                    destination2 = Path.Combine(file.DirectoryName, destination);
                                if (Directory.Exists(destination2) || destination2.EndsWith(DataFuns.DirSeparator)) destination2 = Path.Combine(destination2, file.Name);
                                FileInfo file2 = new FileInfo(destination2);
                                if (!file2.Directory.Exists) file2.Directory.Create();
                                if (file2.Exists) file2.Delete();
                                file.MoveTo(destination2);
                                LOG_MESSAGE = "成功。";
                            }
                            else
                                LOG_MESSAGE = "找不到文件。";
                        }
                    }
                    else if (CMD_NAME.ToLower().Equals("del"))
                    {
                        if (PARAM_LIST.Contains("*") || PARAM_LIST.Contains("?"))
                        {
                            int idx = PARAM_LIST.LastIndexOf(DataFuns.DirSeparator);
                            if (idx > 0)
                            {
                                DirectoryInfo dinfo = new DirectoryInfo(PARAM_LIST.Substring(0, idx));
                                if (dinfo.Exists)
                                {
                                    FileInfo[] files = dinfo.GetFiles(PARAM_LIST.Substring(idx + 1), SearchOption.TopDirectoryOnly);
                                    foreach (FileInfo file in files)
                                    {
                                        file.Delete();
                                    }
                                    LOG_MESSAGE = "删除成功。";
                                }
                            }
                        }
                        else
                        {
                            if (Directory.Exists(PARAM_LIST))
                            {
                                Directory.Delete(PARAM_LIST, true);
                                LOG_MESSAGE = "目录删除成功。";
                            }
                            else if (File.Exists(PARAM_LIST))
                            {
                                File.Delete(PARAM_LIST);
                                LOG_MESSAGE = "删除成功。";
                            }
                            else
                                LOG_MESSAGE = "文件或目录不存在。";
                        }
                    }
                    else if (CMD_NAME.ToLower().Equals("md"))
                    {
                        DirectoryInfo dirinfo = new DirectoryInfo(PARAM_LIST);
                        if (!dirinfo.Exists)
                        {
                            dirinfo.Create();
                            LOG_MESSAGE = "创建目录成功。";
                        }
                    }
                    else
                    {
                        if (CMD_NAME.ToLower().Equals("cmd"))
                        {
                            string[] args = PARAM_LIST.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
                            LOG_MESSAGE = InvokeDynamic.InvokeCMD("", args);
                        }
                        else
                        {
                            LOG_MESSAGE = CommFuns.Execute(CMD_NAME, PARAM_LIST);
                        }
                    }
                    lock (task_Lock)
                    {
                        msg.Rows.Add(new object[] { SQLCMD_ID, LOG_MESSAGE });
                    }
                    if (task_id.Length > 0)
                    {
                        LOG_MESSAGE += PARAM_LIST;
                        DateTime EXECUTE_END_TIME = DateTime.Now;
                        if (LOG_MESSAGE.Length > 4000) LOG_MESSAGE = LOG_MESSAGE.Substring(0, 4000);
                        sql = "INSERT INTO TB_SQLCMD_LOG(TASK_ID,SQLCMD_ID,FUNCTION_ID,TRADEDATE,EXECUTED_FLAG,EXECUTE_START_TIME,EXECUTE_END_TIME,LOG_MESSAGE) VALUES(" + bif.ParamChar + "TASK_ID," + bif.ParamChar + "SQLCMD_ID," + bif.ParamChar + "FUNCTION_ID," + bif.ParamChar + "TRADEDATE,'2'," + bif.ParamChar + "EXECUTE_START_TIME," + bif.ParamChar + "EXECUTE_END_TIME," + bif.ParamChar + "LOG_MESSAGE)";
                        sql_params.Add(new DbParam("FUNCTION_ID", function_id, DbParamType.Int, false));
                        sql_params.Add(new DbParam("TRADEDATE", tradedate, DbParamType.VarChar, false));
                        sql_params.Add(new DbParam("EXECUTE_START_TIME", EXECUTE_START_TIME, DbParamType.DateTime, false));
                        sql_params.Add(new DbParam("EXECUTE_END_TIME", EXECUTE_END_TIME, DbParamType.DateTime, false));
                        sql_params.Add(new DbParam("LOG_MESSAGE", LOG_MESSAGE, DbParamType.NVarChar, false));
                        bif.ExecUpdate(sql, sql_params);
                    }
                }
            }
        }
        /// <summary>
        /// 后台任务对象
        /// </summary>
        public BackgroundWorker BackgroundWorkerTask
        {
            get
            {
                return bwt;
            }
            set
            {
                bwt = value;
            }
        }

        /// <summary>
        /// 释放内存
        /// </summary>
        public void Dispose()
        {
            try
            {
                GC.Collect();
            }
            catch { }
        }

        /// <summary>
        /// 析构函数
        /// </summary>
        ~SqlcmdTask()
        {
            Dispose();
        }
    }
}
